package com.xuanyuan.config;

import com.xuanyuan.domain.AjaxResult;
import com.xuanyuan.enums.ExceptionEnum;
import com.xuanyuan.exception.BusinessException;
import com.xuanyuan.exception.ErrorPageException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.ServletException;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.io.IOException;
import java.util.stream.Collectors;

/**
 * RestControllerAdvice，统一异常处理
 */
@Slf4j
@RestControllerAdvice
public class ExceptionHandlerConfig {

    /**
     * 处理其他异常
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public AjaxResult handler(Exception e) {
        if (e instanceof BusinessException) {
            BusinessException myException = (BusinessException) e;
            return AjaxResult.error(myException.getCode(), myException.getMessage());
        } else if (e instanceof IOException) {
            return AjaxResult.error(ExceptionEnum.INTERNAL_SERVER_ERROR.getCode(), "io异常");
        } else {
            log.error("[系统异常] {e}", e);
            return AjaxResult.error(ExceptionEnum.INTERNAL_SERVER_ERROR);
        }
    }

    /**
     * 处理自定义业务异常
     */
    @ExceptionHandler(value = BusinessException.class)
    @ResponseBody
    public AjaxResult business(BusinessException e) {
        log.error("自定义业务异常！原因是:", e);
        return AjaxResult.error(e.getCode(), e.getErrorMsg());
    }

    /**
     * 处理自定义页面错误异常
     */
    @ExceptionHandler(value = ErrorPageException.class)
    @ResponseBody
    public AjaxResult errorPage(ErrorPageException e) {
        log.error("自定义页面错误异常！原因是:", e);
        return AjaxResult.error(e.getCode(), e.getErrorMsg());
    }

    /**
     * 处理空指针的异常
     */
    @ExceptionHandler(value = NullPointerException.class)
    @ResponseBody
    public AjaxResult exceptionHandler(NullPointerException e) {
        log.error("发生空指针异常！原因是:", e);
        return AjaxResult.error(500, "空指针异常:" + e.getMessage());
    }

    /**
     * 处理RequestBody请求体调用接口校验失败抛出的异常
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    @ResponseBody
    public AjaxResult exceptionHandler(MethodArgumentNotValidException e) {

        log.error("参数校验异常(RequestBody):", e);
        String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining("; "));
        return AjaxResult.error(400, message);
    }

    /**
     * 处理 form data方式调用接口校验失败抛出的异常
     */
    @ExceptionHandler(value = BindException.class)
    @ResponseBody
    public AjaxResult bindExceptionHandler(BindException e) {

        log.error("参数校验异常(form data):", e);
        String message = e.getBindingResult().getAllErrors().stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining("; "));
        return AjaxResult.error(400, message);
    }

    /**
     * 处理单个参数校验失败抛出的异常
     */
    @ExceptionHandler(value = ConstraintViolationException.class)
    @ResponseBody
    public AjaxResult constraintViolationExceptionHandler(ConstraintViolationException e) {

        log.error("参数校验异常(单个参数):", e);
        String message = e.getConstraintViolations().stream().map(ConstraintViolation::getMessage).collect(Collectors.joining("; "));
        return AjaxResult.error(400, message);
    }

    /**
     * 处理参数校验异常 --Json 转换异常
     */
    @ExceptionHandler(value = HttpMessageNotReadableException.class)
    @ResponseBody
    public AjaxResult exceptionHandler(HttpMessageNotReadableException e) {
        log.error("参数校验异常-json转换异常:", e);
        return AjaxResult.error(400, "参数校验异常-json转换异常:" + e.getMessage());
    }

    /**
     * servlet异常
     */
    @ExceptionHandler
    public AjaxResult handleServletException(ServletException ex) {
        return AjaxResult.error(500, "servlet异常:" + ex.getMessage());
    }

}

